package com.yykj.backstage.all.service.impl;

import com.google.common.base.Joiner;
import com.yykj.backstage.all.converter.AdminDTOConverter;
import com.yykj.backstage.all.converter.AdminRoleDTOConverter;
import com.yykj.backstage.all.dto.*;
import com.yykj.backstage.all.form.AdminEditForm;
import com.yykj.backstage.all.form.AdminMenuForm;
import com.yykj.backstage.all.form.AdminRoleForm;
import com.yykj.backstage.all.form.LoginForm;
import com.yykj.backstage.all.model.entity.Admin;
import com.yykj.backstage.all.model.entity.AdminOauth;
import com.yykj.backstage.all.model.entity.AdminRole;
import com.yykj.backstage.all.model.repository.AdminOauthRepository;
import com.yykj.backstage.all.model.repository.AdminRepository;
import com.yykj.backstage.all.model.repository.AdminRoleRepository;
import com.yykj.backstage.all.service.AdminService;
import com.yykj.common.constant.CommonConstant;
import com.yykj.common.constant.RedisConstant;
import com.yykj.common.enums.ResultEnums;
import com.yykj.common.exception.NormalException;
import com.yykj.common.service.RedisService;
import com.yykj.common.util.GsonUtil;
import com.yykj.common.util.LocalObjectUtil;
import com.yykj.common.util.LocalRequestUtil;
import com.yykj.common.util.LocalStringUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

@Service
public class AdminServiceImpl implements AdminService {

    @Override
    public AdminLoginInfo login(LoginForm loginForm) {
        Admin admin = adminRepository.findFirstByUsernameAndPassword(loginForm.getUsername(), LocalStringUtil.encrypt(loginForm.getPassword()));
        if (admin == null) {
            //TODO 次数限制
            throw new NormalException(ResultEnums.LOGIN_FAIL);
        }
        String token = LocalStringUtil.getUUID();
        AdminLoginInfo info = new AdminLoginInfo();
        BeanUtils.copyProperties(admin, info);
        info.setToken(token);

        info.setAdminMenu(getAdminMenu(admin.getId()));

        redisService.set(token, GsonUtil.toJson(info), RedisConstant.LOGIN_EXPIRE);

        return info;
    }

    @Override
    public AdminLoginInfo loginInfo(String token) {
        String s = redisService.get(token);
        AdminLoginInfo info = GsonUtil.fromJson(s, AdminLoginInfo.class);
        redisService.set(token, s, RedisConstant.LOGIN_EXPIRE);
        return info;
    }

    @Override
    public List<AdminMenu> getAdminMenu(Integer adminId) {
        Admin admin = adminRepository.findById(adminId).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        List<AdminOauth> adminOauthList;
        if (admin.getUsername().equals("admin") || StringUtils.isEmpty(admin.getRoleIds())) {
            adminOauthList = oauthRepository.findAll();
        } else {
            String[] split = admin.getRoleIds().split(",");
            List<Integer> groupIds = new ArrayList<>();
            for (String s : split) {
                groupIds.add(Integer.parseInt(s));
            }
            List<AdminRole> groups = roleRepository.findAllByIdIn(groupIds);
            List<Integer> oauthIds = new ArrayList<>();
            for (AdminRole group : groups) {
                String[] split1 = group.getOauthIds().split(",");
                for (String s : split1) {
                    oauthIds.add(Integer.parseInt(s));
                }
            }
            adminOauthList = oauthRepository.findAllByIdIn(oauthIds);

        }

        return formatAdminMenu(adminOauthList);
    }

    private   List<AdminMenu> formatAdminMenu(List<AdminOauth> list){
        List<AdminMenu> result = new ArrayList<>();
        for (AdminOauth oauth : list) {
            if (oauth.getPid() == 0) {
                AdminMenu adminMenu = new AdminMenu();
                BeanUtils.copyProperties(oauth, adminMenu);
                for (AdminOauth child : list) {
                    if (oauth.getId().equals(child.getPid())) {
                        AdminSubMenu subMenu = new AdminSubMenu();
                        BeanUtils.copyProperties(child, subMenu);
                        adminMenu.getChild().add(subMenu);
                    }
                }
                result.add(adminMenu);
            }
        }
        return result;
    }

    @Override
    public AdminOauth editMenu(AdminMenuForm form) {
        AdminOauth adminOauth = new AdminOauth();
        LocalObjectUtil.copyNullValue(form, adminOauth);
        adminOauth = oauthRepository.save(adminOauth);
        return adminOauth;
    }

    @Override
    public void deleteMenu(Integer id) {
        AdminOauth adminOauth = oauthRepository.findById(id).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        //检查是否是父级菜单
        if(adminOauth.getPid()!=null && adminOauth.getPid().equals(0)){
            List<AdminOauth> allByPid = oauthRepository.findAllByPid(adminOauth.getPid());
            if(allByPid!=null && allByPid.size() >0){
                throw new NormalException(ResultEnums.MENU_HAS_CHILD_MENU);
            }
        }

        oauthRepository.delete(adminOauth);
    }

    @Override
    public AdminRoleDTO editRole(AdminRoleForm form) {
        AdminRole adminRole;
        if (form.getId() != null && form.getId() > 0) {//修改
            adminRole = roleRepository.findById(form.getId()).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        } else {//新增
            adminRole = new AdminRole();
        }
        BeanUtils.copyProperties(form, adminRole);
        if(CollectionUtils.isEmpty(form.getOauthIds())){
            adminRole.setOauthIds("");
        }else{
            adminRole.setOauthIds(Joiner.on(',').join(form.getOauthIds()));
        }

        adminRole = roleRepository.save(adminRole);
        return AdminRoleDTOConverter.convert(adminRole);
    }

    @Override
    public void deleteRole(Integer groupId) {
        AdminRole group = roleRepository.findById(groupId).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        roleRepository.delete(group);
    }

    @Override
    public void deleteAdmin(Integer adminId) {
        adminRepository.deleteById(adminId);
    }

    @Override
    public AdminDTO editAdmin(AdminEditForm adminEditForm) {
        if(StringUtils.isEmpty(adminEditForm.getUsername())){
            throw new NormalException(ResultEnums.PARAM_ERROR);
        }

        Admin admin;
        if (adminEditForm.getId() != null && adminEditForm.getId() > 0) {
            admin = adminRepository.findById(adminEditForm.getId()).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        } else {
            admin = new Admin();
            Admin firstByUsername = adminRepository.findFirstByUsername(adminEditForm.getUsername());
            if(firstByUsername!=null){
                throw new NormalException(ResultEnums.ALL_READY_EXIST);
            }
        }

        BeanUtils.copyProperties(adminEditForm, admin);
        if (StringUtils.isEmpty(adminEditForm.getRoleIds())) {
            admin.setRoleIds("");
        }else{
            admin.setRoleIds(Joiner.on(',').join(adminEditForm.getRoleIds()));
        }

        admin.setPassword(LocalStringUtil.encrypt(CommonConstant.DEFAULT_PASSWORD));

        adminRepository.save(admin);

        return AdminDTOConverter.convert(admin);
    }

    @Override
    public List<AdminDTO> getAdminList() {
        List<Admin> all = adminRepository.findAll();
        return AdminDTOConverter.convert(all);
    }

    @Override
    public List<AdminRoleDetailDTO> listRole() {
        List<AdminRole> all = roleRepository.findAll();

        List<AdminRoleDetailDTO> result = new ArrayList<>();
        for (AdminRole role:all){
            AdminRoleDetailDTO d = new AdminRoleDetailDTO();
            BeanUtils.copyProperties(role,d);
            if(StringUtils.isEmpty(role.getOauthIds())){
                d.setOauth(new ArrayList<>());
            }else{
                String[] strings = role.getOauthIds().split(",");
                List<Integer> ids = new ArrayList<>();
                for (String s:strings){
                    ids.add(Integer.parseInt(s));
                }
                List<AdminOauth> allByIdIn = oauthRepository.findAllByIdIn(ids);

                d.setOauth(formatAdminMenu(allByIdIn));
            }
            result.add(d);
        }
        return result;
    }

    @Override
    public void logout() {
        String token = LocalRequestUtil.getToken();
        redisService.remove(token);
    }

    @Override
    public void changeAdminPassword(AdminPasswordDTO adminPasswordDTO) {
        if(!StringUtils.hasText(adminPasswordDTO.getPassword()) || !StringUtils.hasText(adminPasswordDTO.getRePassword())
        || !adminPasswordDTO.getPassword().equals(adminPasswordDTO.getRePassword())){
            throw new NormalException(ResultEnums.PASSWORD_ERROR,"两次密码不一至");
        }
        Admin admin = adminRepository.findById(adminPasswordDTO.getAdminId()).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        if(!admin.getPassword().equals(LocalStringUtil.encrypt(adminPasswordDTO.getOldPassword()))){
            throw new NormalException(ResultEnums.PASSWORD_ERROR);
        }
        admin.setPassword(LocalStringUtil.encrypt(adminPasswordDTO.getPassword()));
        adminRepository.save(admin);
    }

    private AdminLoginInfo getAdminLoginInfo() {
        String token = LocalRequestUtil.getToken();
        if (StringUtils.isEmpty(token)) {
            throw new NormalException(ResultEnums.NOT_LOGIN);
        }
        String s = redisService.get(token);
        if (StringUtils.isEmpty(s)) {
            throw new NormalException(ResultEnums.NOT_LOGIN);
        }
        AdminLoginInfo info = GsonUtil.fromJson(s, AdminLoginInfo.class);
        if (info == null) {
            throw new NormalException(ResultEnums.NOT_LOGIN);
        }

        return info;

    }

    private RedisService redisService;

    private AdminRepository adminRepository;

    private AdminRoleRepository roleRepository;

    private AdminOauthRepository oauthRepository;

    @Autowired
    public void setRedisService(RedisService redisService) {
        this.redisService = redisService;
    }

    @Autowired
    public void setAdminRepository(AdminRepository adminRepository) {
        this.adminRepository = adminRepository;
    }

    @Autowired
    public void setRoleRepository(AdminRoleRepository roleRepository) {
        this.roleRepository = roleRepository;
    }

    @Autowired
    public void setOauthRepository(AdminOauthRepository oauthRepository) {
        this.oauthRepository = oauthRepository;
    }

}
